#ifndef NANE_D3D9RENDERSYSTEM_H
#   define NANE_D3D9RENDERSYSTEM_H

#   include "nane/RenderSystem/IRenderSystem.h"
#   include <d3d9.h>

namespace nane
{
    struct D3D9ConstantBuffer;
    
    class D3D9RenderSystem
        : public IRenderSystem
    {
    public:
        D3D9RenderSystem();
        ~D3D9RenderSystem();

    public:
        bool Initialize();
        void Shutdown();
        bool InitializeContext( IWindow::OSHandle _windowHandle, uint32 _resWidth, uint32 _resHeight );
        IVertexBuffer* CreateVertexBuffer( EResourceUsage::raw_type _usage, uint32 _verticesNum, uint32 _vertexSize
                                         , VertexElement* _elements, uint32 _elementsNum, byte* _initData );
        void ReleaseVertexBuffer( IVertexBuffer* _vertexBuffer );
        byte* LockVertexBuffer( IVertexBuffer* _vertexBuffer, uint32 _offset, uint32 _size );
        void UnlockVertexBuffer( IVertexBuffer* _vertexBuffer );
        void SetVertexBuffer( uint16 _streamNumber, IVertexBuffer* _vertexBuffer );
        IIndexBuffer* CreateIndexBuffer( EResourceUsage::raw_type _usage, uint32 _indiciesNum, uint16* _initData );
        void ReleaseIndexBuffer( IIndexBuffer* _indexBuffer );
        uint16* LockIndexBuffer( IIndexBuffer* _indexBuffer, uint32 _offset, uint32 _size );
        void UnlockIndexBuffer( IIndexBuffer* _indexBuffer );
        void SetIndexBuffer( IIndexBuffer* _indexBuffer );
        ITexture* CreateTexture( EResourceUsage::raw_type _usage, uint32 _width, uint32 _height, EPixelFormat::raw_type _format );
        void ReleaseTexture( ITexture* _texture );
        byte* LockTexture( ITexture* _texture, uint32 _x, uint32 _y, uint32 _width, uint32 _height, uint32* _pitch );
        void UnlockTexture( ITexture* _texture );
        void SetTexture( uint32 _stage, ITexture* _texture );
        bool SetRenderTarget( IRenderTarget* _target );
        bool BeginScene();
        void EndScene();
        void DrawPrimitive( EPrimitiveType::raw_type _type, uint32 _startVertex, uint32 _primitiveCount );
        void DrawIndexedPrimitive( EPrimitiveType::raw_type _type, uint32 _baseVertexIndex, uint32 _minIndex
                                         , uint32 _verticesNum, uint32 _startIndex, uint32 _primitiveCount );
        void ClearRenderTarget( EFrameBufferType::raw_type _type, uint32 _color, float _depth, uint16 _stencil );
        void SwapBuffers();
        void SetProjectionMatrix( const float* _projection );
        void SetModelViewMatrix( const float* _modelview );
        void SetLightingEnable( bool _enable );
        void SetCullMode( ECullMode::raw_type _mode );
        
        IConstantBuffer* CreateConstantBuffer( uint32 _size );
        bool PushConstantF( IConstantBuffer* _constantBuffer, uint32 _offset, float* _constant, uint32 _size );
        bool PushConstantI( IConstantBuffer* _constantBuffer, uint32 _offset, int* _constant, uint32 _size );
        bool PushConstantB( IConstantBuffer* _constantBuffer, uint32 _offset, bool* _constant, uint32 _size );
        void ReleaseConstantBuffer( IConstantBuffer* _constantBuffer );

        IVertexShader* CreateVertexShader( const byte* _buffer, uint32 _size );
        bool SetVertexShader( IVertexShader* _vertexShader );
        bool SetVertexShaderConstantBuffer( uint32 _slot, IConstantBuffer* _constantBuffer );
        void ReleaseVertexShader( IVertexShader* _vertexShader );
        
        IPixelShader* CreatePixelShader( const byte* _buffer, uint32 _size );
        bool SetPixelShader( IPixelShader* _pixelShader );
        bool SetPixelShaderConstantBuffer( uint32 _slot, IConstantBuffer* _constantBuffer );
        void ReleasePixelShader( IPixelShader* _pixelShader );

    private:
        IDirect3DVertexDeclaration9* createVertexDeclaration_( VertexElement* _elements, uint32 _elementsNum );

    private:
        static D3DFORMAT s_findMatchingZFormat_( IDirect3D9* _pD3D, UINT _adapter, D3DDEVTYPE _devtype, D3DFORMAT _bbufferfmt, bool _stencil );
        
    private:
        IDirect3D9* m_pD3D;
        HMODULE m_hDLL;
        D3DPRESENT_PARAMETERS m_presentParams;
        IDirect3DDevice9* m_pDevice;
        D3DDISPLAYMODE m_systemDisplayMode;
        D3D9ConstantBuffer* m_activeVertexConstantBuffer;
        uint32 m_activeVertexConstantBufferSlot;
        D3D9ConstantBuffer* m_activePixelConstantBuffer;
        uint32 m_activePixelConstantBufferSlot;
    };
}   // namespace nane

#endif	// NANE_D3D9RENDERSYSTEM_H
